import os.path
import re
import time
from tokenize import TokenError

from django.http import FileResponse
from django.shortcuts import render
from rest_framework import status,mixins
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet
from rest_framework_simplejwt.exceptions import InvalidToken
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated


# Create your views here.
#更改登录显示字段 重写+路由配置
from rest_framework_simplejwt.views import TokenObtainPairView

from user.models import User, Addr, VerCode
from user.permissions import UserPermissions, AddrPermissions
from user.serializers import UserSerializer, AddrSerializer
from web02.settings import MEDIA_ROOT


#用户登录接口
class LoginView(TokenObtainPairView):
    #重写post 前端是用post请求过来的
    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        try:
            serializer.is_valid(raise_exception=True)
        except TokenError as e:
            raise InvalidToken(e.args[0])
        #自定义登录成功返回结果
        result=serializer.validated_data
        #添加登录的字段
        result['id'] = serializer.user.id
        result['mobile']=serializer.user.mobile
        result['email']=serializer.user.email
        result['username'] = serializer.user.username
        #重新给access取名
        result['token'] = result.pop('access')
        return Response(result, status=status.HTTP_200_OK)

#用户注册接口
class RegisterView(APIView):
    def post(self,request):
        #1接收用户参数
        username=request.data.get('username')
        password = request.data.get('password')
        email = request.data.get('email')
        possword_confirmation=request.data.get('possword_confirmation')
        #2参数校验
        if not all([username,password,email,possword_confirmation]):
            return Response({'error':'所有参数不能为空'},status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #校验用户名
        if User.objects.filter(username=username).exists():
            return Response({'error': '用户名以存在'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #校验密码
        if password !=possword_confirmation:
            return Response({'error': '两次密码不一致'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #校验密码长度
        if not (6<=len(password)<=18):
            return Response({'error': '密码长度需在6到18之间'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #校验邮箱
        if User.objects.filter(email=email).exists():
            return Response({'error': '该邮箱已被注册'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #校验邮箱格式
        if not re.match(r'^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$',email):
            return Response({'error': '邮箱格式有误'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #3创建用户
        obj=User.objects.create_user(username=username,email=email,password=password)
        res={
            "username":username,
            'id':obj.id,
            'email':obj.email
        }
        return Response(res,status=status.HTTP_201_CREATED)

#获取用户信息接口 单个
class UserView(GenericViewSet,mixins.RetrieveModelMixin):
    #获取用户信息
    queryset = User.objects.all()
    serializer_class = UserSerializer
    #添加权限认证  仅登录访问
    permission_classes = [IsAuthenticated,UserPermissions]
    #更新用户头像
    def upload_avatar(self, request, *args, **kwargs):
        #上传用户头像
        avatar=request.data.get('avatar')
        #校验是否有上传文件
        if not avatar:
            return Response({'error': '上传失败，文件不能为空'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #校验文件大小不能超过300kb
        if avatar.size>1024*300:
            return Response({'error': '上传失败，文件大小不能超过300kb'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #保存文件
        user=self.get_object()
        #获取序列化对象
        ser=self.get_serializer(user,data={'avatar':avatar},partial=True)
        #进行校验
        ser.is_valid(raise_exception=True)
        ser.save()
        return Response({'url':ser.data['avatar']})

    @staticmethod
    def ver_code(code,codeID,mobile):
        """验证码校验通用逻辑"""
        # # 1获取参数
        # code = request.data.get('code')  # 获取验证码
        # codeID = request.data.get('codeID')  # 验证码ID
        # mobile = request.data.get('mobile')
        # 2、校验参数
        if not code:
            return {'error': '验证码不能为空'}
        if not codeID:
            return {'error': '验证码ID不能为空'}
        if not mobile:
            return {'error': '手机号不能为空'}
        # 3、校验验证码
        if VerCode.objects.filter(id=codeID, code=code, mobile=mobile).exists():
            # 校验验证码是否过期
            # 获取验证码创建时间
            c_obj = VerCode.objects.get(id=codeID, code=code, mobile=mobile)
            # 获取验证码时间戳
            ct = c_obj.create_time.timestamp()
            # 获取当前时间的时间戳
            et = time.time()
            # 删除验证码（避免用户在有效期内使用同一个验证码重复请求）
            c_obj.delete()
            if ct + 180 <= et:
                return {'error': '验证码已过期'}
        else:
            return {'error': '验证失败，请重新获取'}

    #绑定手机号
    def bind_mobile(self, request, *args, **kwargs):
        # #1获取参数
        code=request.data.get('code') #获取验证码
        codeID=request.data.get('codeID') #验证码ID
        mobile=request.data.get('mobile')
        # #2、校验参数
        # if not code:
        #     return Response({'error':'验证码不能为空'},status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        # if not codeID:
        #     return Response({'error': '验证码ID不能为空'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        # if not mobile:
        #     return Response({'error': '手机号不能为空'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        # #3、校验验证码
        # if VerCode.objects.filter(id=codeID,code=code,mobile=mobile).exists():
        #     #校验验证码是否过期
        #     #获取验证码创建时间
        #     c_obj=VerCode.objects.get(id=codeID,code=code,mobile=mobile)
        #     #获取验证码时间戳
        #     ct=c_obj.create_time.timestamp()
        #     #获取当前时间的时间戳
        #     et=time.time()
        #     #删除验证码（避免用户在有效期内使用同一个验证码重复请求）
        #     c_obj.delete()
        #     if ct+180<=et:
        #         return Response({'error': '验证码已过期'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        # else:
        #     return Response({'error': '验证失败，请重新获取'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #4、绑定手机号
        #校验手机号
        if User.objects.filter(mobile=mobile).exists():
            return Response({'error':'一个手机号只能绑定一个用户'},status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #绑定手机号
        user=request.user
        user.mobile=mobile
        user.save()
        return Response({'message':'绑定成功'},status=status.HTTP_200_OK)

    #解绑手机
    def unbind_mobile(self, request, *args, **kwargs):
        #1、获取参数
        code = request.data.get('code')  # 获取验证码
        codeID = request.data.get('codeID')  # 验证码ID
        mobile = request.data.get('mobile')
        #2、校验参数
        # 3、校验验证码
        request=self.ver_code(code,codeID,mobile)
        if request:
            return Response(request,status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #4、解绑手机
        user=request.user
        if user.mobile==mobile:
            user.mobile=''
            user.save()
            return Response({'message': '解绑成功'},status=status.HTTP_200_OK)
        else:
            return Response({'error': '当前用户没有绑定该号码'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)

    #修改用户昵称
    def update_name(self, request, *args, **kwargs):
        #1、获取参数
        last_name=request.data.get('last_name')
        #2、校验参数
        if not last_name:
            return Response({'error': '昵称不能为空'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #3、修改用户名
        #获取用户等同于request.user
        user=self.get_object()
        user.last_name=last_name
        user.save()
        return Response({'message':'修改成功'},status=status.HTTP_200_OK)
    
    #修改邮箱
    def update_email(self, request, *args, **kwargs):
        """修改邮箱视图"""
        #1、获取参数
        email=request.data.get('email')
        user=self.get_object()
        #2、校验参数
        # 参数不能为空
        if not email:
            return Response({'error': '邮箱不能为空'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #校验邮箱格式是否正确
        if not re.match(r'([A-Za-z0-9]+[.-_])*[A-Za-z0-9]+@[A-Za-z0-9-]+(\.[A-Z|a-z]{2,})+',email):
            return Response({'error': '邮箱格式有误'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #邮箱有没有被其他用户绑定
        if User.objects.filter(email=email).exists():
            return Response({'error': '该邮箱已被其他用户绑定'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        if user.email==email:
            return Response({'message': 'ok'}, status=status.HTTP_200_OK)
        #3、修改邮箱
        user.email=email
        user.save()
        return Response({'message':'ok'},status=status.HTTP_200_OK)

    #修改用户密码
    def update_password(self, request, *args, **kwargs):
        """修改密码"""
        user = self.get_object()
        #1、获取参数
        code=request.data.get('code')
        codeID = request.data.get('codeID')
        mobile = request.data.get('mobile')
        password = request.data.get('password')
        possword_confirmation = request.data.get('possword_confirmation')
        #2、校验验证码
        result=self.ver_code(code,codeID,mobile)
        if result:
            return Response(result,status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #校验手机号是否一致
        if user.mobile !=mobile:
            return Response({'error':'不是绑定手机号'},status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        # 3、校验密码
        if not password:
            return Response({'error': '密码不能为空'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        if password !=possword_confirmation:
            return Response({'error': '两次密码不一致'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        #4、修改密码
        user.set_password(password) #加密修改
        user.save()
        return Response({'message':'ok'},status=status.HTTP_200_OK)



#文件接口
class FileView(APIView):
    #获取文件视图
    def get(self,requests,name):
        #路径名为
        path=MEDIA_ROOT / name
        #判断是否存在文件
        if os.path.isfile(path):
            return FileResponse(open(path,'rb'))
        return Response({'error':'文件不存在'},status=status.HTTP_404_NOT_FOUND)


class AddrView(GenericViewSet,
               mixins.ListModelMixin, #地址列表
               mixins.CreateModelMixin, #添加
               mixins.DestroyModelMixin, #删除
               mixins.UpdateModelMixin):    #修改
    #地址管理视图
    queryset = Addr.objects.all()
    serializer_class = AddrSerializer
    #设置认证用户才能访问
    permission_classes = [IsAuthenticated,AddrPermissions]
    #指定过滤字段
    # filterset_fields=('user',)
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        #通过请求过来认证的用户进行过滤
        queryset=queryset.filter(user=request.user)
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)
    def set_default_addr(self,request, *args, **kwargs):
        """设置默认收货地址"""
        #1、获取到要设置的地址对象
        obj=self.get_object()
        obj.is_default=True
        obj.save()
        #2、将该地址设置为默认的收货地址，将用户的其他地址设置为非默认
        queryset=self.get_queryset().filter(user=request.user)
        for item in queryset:
            if item != obj:
                item.is_default=False
                item.save()
        return Response({'message':'设置成功'},status=status.HTTP_200_OK)



